package com.lanjiu.lib.imclient.ims;

import com.lanjiu.lib.NettyHost;
import com.lanjiu.lib.communication.IMSClientFactory;
import com.lanjiu.lib.communication.IMSConfig;
import com.lanjiu.lib.communication.callback.OnConnectStatusCallback;
import com.lanjiu.lib.communication.interf.IMSClientInterface;
import com.lanjiu.lib.imclient.bus.MessageEvent;
import com.lanjiu.lib.imclient.ims.read.IMSMessageReader;
import com.lanjiu.lib.imclient.ims.send.IMSMessageSender;
import com.lanjiu.lib.utils.CollectionUtils;
import com.lanjiu.lib.utils.log.Logger;
import com.lanjiu.lib.utils.th.Threader;
import com.lanjiu.pro.business.BusinessProtocolMessageStandard;
import com.ljkj.cordial.chat.presenter.ChatMainPresenter;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @description:
 * @author: Panwei
 * @date: 2019/11/8 17:02
 */
public class IMSClientHelper {

    public static final int CONNECT_STATUS_ING = 0;
    public static final int CONNECT_STATUS_SUCC = 1;
    public static final int CONNECT_STATUS_FAIL = 2;

    private static final String SEND_TYPE_REQUEST = "req_";
    private static final String SEND_TYPE_MESSAGE = "msg_";

    private int mCurrentConnectStatus = CONNECT_STATUS_FAIL;
    private Map<String, BusinessProtocolMessageStandard.CheckUnifiedEntranceMessage> mMessageQueueMap;
    private static IMSClientHelper mInstance;
    private boolean isLoop = false;
    private boolean isHasMessage;
    private long mNoMessageTimestamp;
    private ExecutorService mIMSConnectLoopPool;
    private ExecutorService mMessageSendLoopPool;
    private ExecutorService mAnalyticParamsPool;// 解析参数线程池(发送语音或图片时需要IO读取文件所以放在线程里)
    private IMSClientInterface mIMSClient;
    private IMSMessageReader mMessageReader;
    private IMSMessageSender mMessageSender;
    private OnConnectStatusChangedListener mConnectStatusChangedListener;
    private OnConnectStatusCallback mConnectStatusCallback = new OnConnectStatusCallback() {
        @Override
        public void onConnecting() {
            mCurrentConnectStatus = CONNECT_STATUS_ING;
            if (mConnectStatusChangedListener != null)
                mConnectStatusChangedListener.onConnectStatusChanged(CONNECT_STATUS_ING);
        }

        @Override
        public void onConnected() {
            mCurrentConnectStatus = CONNECT_STATUS_SUCC;
            if (mConnectStatusChangedListener != null)
                mConnectStatusChangedListener.onConnectStatusChanged(CONNECT_STATUS_SUCC);
            if (mIMSConnectLoopPool != null)
                mIMSConnectLoopPool.shutdownNow();
            startMessageSendLoop();
        }

        @Override
        public void onConnectFailed() {
            mCurrentConnectStatus = CONNECT_STATUS_FAIL;
            if (mConnectStatusChangedListener != null)
                mConnectStatusChangedListener.onConnectStatusChanged(CONNECT_STATUS_FAIL);
            stopMessageSendLoop(false);
        }
    };

    public static IMSClientHelper getInstance() {
        if (mInstance == null) {
            synchronized (IMSClientHelper.class) {
                if (mInstance == null) {
                    // 使用双重同步锁
                    mInstance = new IMSClientHelper();
                }
            }
        }
        return mInstance;
    }

    private IMSClientHelper() {
        mMessageReader = new IMSMessageReader();
        mMessageSender = new IMSMessageSender();
        mAnalyticParamsPool = Executors.newFixedThreadPool(5);
        mMessageQueueMap = new ConcurrentHashMap<>();
    }

    public void connect() {
        if (mCurrentConnectStatus == CONNECT_STATUS_FAIL) {
            if (mIMSConnectLoopPool == null || mIMSConnectLoopPool.isShutdown() || mIMSConnectLoopPool.isTerminated()) {
                mIMSConnectLoopPool = Executors.newSingleThreadExecutor();
            }
            mIMSConnectLoopPool.execute(() -> {
                if (mIMSClient == null) {
                    mCurrentConnectStatus = CONNECT_STATUS_ING;
                    mIMSClient = IMSClientFactory.getTCPClient();
                    mIMSClient.init(NettyHost.BUSINESS_COMMUNICATION_HOST, new IMSEventListener(mMessageReader), mConnectStatusCallback);
                } else {
                    if (mIMSClient.isClosed()) {
                        close();
                        connect();
                    } else {
                        if (!mIMSClient.isConnect()) {
                            mCurrentConnectStatus = CONNECT_STATUS_ING;
                            mIMSClient.resetConnect();
                        }
                    }
                }
            });
        }
    }

    public boolean isConnected() {
        if (mIMSClient == null)
            return false;
        return mIMSClient.isConnect();
    }

    public void close() {
        stopMessageSendLoop(true);
        mCurrentConnectStatus = CONNECT_STATUS_FAIL;
        if (mIMSClient != null) {
            mMessageQueueMap.clear();
            mIMSClient.close();
            mIMSClient = null;
        }
    }

    private void sendMessageQueue() {
        if (!CollectionUtils.isEmpty(mMessageQueueMap)) {
            Set<String> keySet = mMessageQueueMap.keySet();
            for (String key : keySet) {
                if (key.startsWith(SEND_TYPE_REQUEST)) {
                    mIMSClient.sendRequestMsg(mMessageQueueMap.get(key));
                    Logger.print("IMSClientHelper", "已发送" + key);
                } else if (key.startsWith(SEND_TYPE_MESSAGE)) {
                    mIMSClient.sendMsg(mMessageQueueMap.get(key));
                    Logger.print("IMSClientHelper", "已发送" + key);
                }
                mMessageQueueMap.remove(key);
            }
        }
    }

    private void checkConnectStatus() {
        if (mCurrentConnectStatus == CONNECT_STATUS_FAIL) {
            connect();
        } else {
            waitTimes();
        }
//        ChatMainPresenter.connect();
    }

    // 有超时，不重发
    public void sendRequest(MessageEvent messageEvent) {
        mAnalyticParamsPool.execute(() -> {
            BusinessProtocolMessageStandard.CheckUnifiedEntranceMessage send = mMessageSender.getSend(messageEvent);
            if (null != send) {
                BusinessProtocolMessageStandard.Head head = send.getUnifiedEntranceMessage().getHead();
                mMessageQueueMap.put(createMapKey(SEND_TYPE_REQUEST, head), send);
            }
        });

        checkConnectStatus();
    }

    // 有超时
    public void sendMessage(MessageEvent messageEvent) {
        mAnalyticParamsPool.execute(() -> {
            BusinessProtocolMessageStandard.CheckUnifiedEntranceMessage send = mMessageSender.getSend(messageEvent);
            if (null != send) {
                BusinessProtocolMessageStandard.Head head = send.getUnifiedEntranceMessage().getHead();
                mMessageQueueMap.put(createMapKey(SEND_TYPE_MESSAGE, head), send);
            }
        });

        checkConnectStatus();
    }

    private String createMapKey(String sendType, BusinessProtocolMessageStandard.Head head) {
        return sendType + head.getUniqueIdentify() + "_" + head.getMsgType();
    }

    public void setConnectStatusChangedListener(OnConnectStatusChangedListener mConnectStatusChangedListener) {
        this.mConnectStatusChangedListener = mConnectStatusChangedListener;
    }

    public interface OnConnectStatusChangedListener {
        void onConnectStatusChanged(int status);
    }

    private void startMessageSendLoop() {
        if (!isLoop) {
            stopMessageSendLoop(false);
            mMessageSendLoopPool = Executors.newSingleThreadExecutor();
            isLoop = true;
            mMessageSendLoopPool.execute(new MessageSendLooper());
            Logger.print("Message send looper started");
        }
    }

    private void stopMessageSendLoop(boolean isCheckMessageQueue) {
        if (isCheckMessageQueue && isConnected()) {
            sendMessageQueue();
        }
        isLoop = false;
        try {
            if (mMessageSendLoopPool != null)
                mMessageSendLoopPool.shutdownNow();
        } catch (Exception e) {
            System.err.println(e.getLocalizedMessage());
        } finally {
            mMessageSendLoopPool = null;
            Logger.print("Message send looper stop");
        }
    }

    private class MessageSendLooper implements Runnable {

        @Override
        public void run() {
            mNoMessageTimestamp = System.currentTimeMillis();
            while (isLoop) {
                if (isConnected()) {
                    if (!CollectionUtils.isEmpty(mMessageQueueMap)) {
                        isHasMessage = true;
                        Set<String> keySet = mMessageQueueMap.keySet();
                        for (String key : keySet) {
                            if (key.startsWith(SEND_TYPE_REQUEST)) {
                                mIMSClient.sendRequestMsg(mMessageQueueMap.get(key));
                                Logger.print("IMSClientHelper", "已发送" + key);
                            } else if (key.startsWith(SEND_TYPE_MESSAGE)) {
                                mIMSClient.sendMsg(mMessageQueueMap.get(key));
                                Logger.print("IMSClientHelper", "已发送" + key);
                            }
                            mMessageQueueMap.remove(key);
                        }
                    } else {
                        if (isHasMessage) {
                            mNoMessageTimestamp = System.currentTimeMillis();
                        }
                        isHasMessage = false;
                        long currentTimestamp = System.currentTimeMillis();
                        if (mNoMessageTimestamp != 0 && currentTimestamp - mNoMessageTimestamp > IMSConfig.MESSAGE_LOOP_MAX_LEISURE_MILLIS) {
                            Logger.print((IMSConfig.MESSAGE_LOOP_MAX_LEISURE_MILLIS / 1000) + "秒内无消息，断开连接");
                            mNoMessageTimestamp = 0;
                            close();
                        }
                    }
                    Threader.sleep(200);
                } else {
                    stopMessageSendLoop(false);
                }
            }
        }
    }

    private void waitTimes() {
        mNoMessageTimestamp = System.currentTimeMillis();
    }

    public void waitForOfflineResponse() {
        Logger.print("等待离线列表多次响应，更新等待时间");
        waitTimes();
    }

    public void onNetworkNotAvailableClear() {
        if (!CollectionUtils.isEmpty(mMessageQueueMap)) {
            for (String key : mMessageQueueMap.keySet()) {
                BusinessProtocolMessageStandard.CheckUnifiedEntranceMessage mMsg = mMessageQueueMap.get(key);
                if (mMsg != null) {
                    BusinessProtocolMessageStandard.UnifiedEntranceMessage msg = mMsg.getUnifiedEntranceMessage();
                    BusinessProtocolMessageStandard.Head head = BusinessProtocolMessageStandard.Head.newBuilder(msg.getHead()).setStatusReport(IMSConfig.STATUS_REPORT_FAILURE).setMsgContentType(IMSConfig.MSG_CONTENT_TYPE_MESSAGE_NETWORK_FAIL).build();
                    BusinessProtocolMessageStandard.UnifiedEntranceMessage unified = BusinessProtocolMessageStandard.UnifiedEntranceMessage.newBuilder(msg).setHead(head).build();
                    if (null != mIMSClient)
                        mIMSClient.getMsgDispatcher().receivedMsg(unified);
                }
                mMessageQueueMap.remove(key);
            }
        }
    }
}
